package com.dj.ms.aop;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dj.common.exception.CentralException;
import com.dj.common.exception.CentralRunException;
import com.dj.common.response.CentralResponse;
import com.dj.common.support.ResponseHandler;
import com.netflix.client.ClientException;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.lang.reflect.UndeclaredThrowableException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

/**
 * <br>
 * <p>rest controller exception process.</p>
 *
 * <br>
 *
 * @author ZJG
 * @version 1.0
 * @date 2021/7/9 下午1:26
 */
@Slf4j
@RestControllerAdvice
public class CentralControllerExceptionAdvice {

     //@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Exception.class)
    public CentralResponse<Object> handleException(Exception ex) {
        if (ObjectUtils.isEmpty(ex)) {
            return ResponseHandler.fail("500", "系统异常");
        }
        log.error("系统异常::{}", ex);
        if (ex instanceof BindException) {
            return ResponseHandler.fail(HttpStatus.BAD_REQUEST.value(), ((BindException) ex).getFieldError().getDefaultMessage());
        }
        if (ex instanceof MethodArgumentNotValidException) {
            return ResponseHandler.fail(HttpStatus.BAD_REQUEST.value(), ((MethodArgumentNotValidException) ex).getBindingResult().getFieldError().getDefaultMessage());
        }
        if (ex instanceof IllegalArgumentException) {
            return ResponseHandler.fail(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
        }
        if (ex instanceof HttpMessageNotReadableException) {
            return ResponseHandler.fail(HttpStatus.BAD_REQUEST.value(), "请求参数不合法");
        }
        if (ex instanceof FeignException.InternalServerError) {
            FeignException.InternalServerError error = (FeignException.InternalServerError) ex;
            return reFeignEx(error);
        }
        if (ex instanceof ClientException) {
            ClientException clientException = (ClientException) ex;
            String s = "未找到服务";
            if (clientException.getErrorType() == ClientException.ErrorType.GENERAL) {
                String[] split = clientException.getErrorMessage().split(":");
                s = split.length > 1? String.format("%s" + s, split[1]) : s;
            }
            return ResponseHandler.fail(HttpStatus.SERVICE_UNAVAILABLE.value(), s);
        }
        if (ex instanceof FeignException) {
            return ResponseHandler.fail("接口异常");
        }
        if (ex instanceof CentralException) {
            CentralException centralException = (CentralException) ex;
            return ResponseHandler.fail(centralException.getCode(), reMsg(centralException.getMessage()));
        }
        if (ex instanceof CentralRunException) {
            CentralRunException runException = (CentralRunException) ex;
            return ResponseHandler.fail(runException.getCode(), reMsg(runException.getMessage()));
        }
        if (ex instanceof UndeclaredThrowableException) {
            UndeclaredThrowableException re = (UndeclaredThrowableException) ex;
            Throwable undeclaredThrowable = re.getUndeclaredThrowable();
            if (undeclaredThrowable instanceof CentralException) {
                CentralException centralException = (CentralException) undeclaredThrowable;
                return ResponseHandler.fail(centralException.getCode(), reMsg(centralException.getMessage()));
            } else if (undeclaredThrowable instanceof CentralRunException) {
                CentralRunException centralRunException = (CentralRunException) undeclaredThrowable;
                return ResponseHandler.fail(centralRunException.getCode(), reMsg(centralRunException.getMessage()));
            } else if (undeclaredThrowable instanceof FeignException.InternalServerError) {
                FeignException.InternalServerError error = (FeignException.InternalServerError) undeclaredThrowable;
                return reFeignEx(error);
            } else if (undeclaredThrowable instanceof FeignException) {
                FeignException error = (FeignException) undeclaredThrowable;
                return reFeignEx(error);
            } else {
                return ResponseHandler.fail("系统异常");
            }
        }
        return ResponseHandler.fail("系统异常");
    }

    private CentralResponse<Object> reFeignEx(Exception ex) {
        FeignException error = (FeignException) ex;
        Optional<ByteBuffer> errByteBuffer = error.responseBody();
        if (ObjectUtil.isNotNull(errByteBuffer) && errByteBuffer.isPresent()) {
            String respStr = new String(errByteBuffer.get().array(), StandardCharsets.UTF_8);
            return ResponseHandler.fail(reCode(respStr), reMsg(respStr));
        }
        return ResponseHandler.fail("接口异常");
    }

    private String reMsg(String message) {
        if (CharSequenceUtil.containsAny(message, "[")) {
            message = message.substring(message.lastIndexOf("["), message.lastIndexOf("]"))
                    .replace("\\[", "")
                    .replace("]", "");
        }
        if (JSONUtil.isJson(message)) {
            JSONObject obj = JSON.parseObject(message);
            if (ObjectUtil.isNotNull(obj) && obj.containsKey("msg")) {
                return obj.getString("msg");
            }
        }

        return CharSequenceUtil.containsAny(message, "FeignException", "InternalServerError")? "API接口异常": message;
    }

    private int reCode(String message) {
        if (CharSequenceUtil.containsAny(message, "[")) {
            message = message.substring(message.lastIndexOf("["), message.lastIndexOf("]"))
                    .replace("\\[", "")
                    .replace("]", "");
        }
        if (JSONUtil.isJson(message)) {
            JSONObject obj = JSON.parseObject(message);
            if (ObjectUtil.isNotNull(obj) && obj.containsKey("code")) {
                return obj.getInteger("code");
            }
        }
        return 500;
    }
}
